/**
 * Copyright (c) 2018, dreamkaylee@foxmail.com All Rights Reserved.
 */

package configuration;

import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.beetl.ext.spring.BeetlGroupUtilConfiguration;
import org.beetl.ext.spring.BeetlSpringViewResolver;
import org.hibernate.validator.HibernateValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.stereotype.Controller;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.Import;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.common.exception.AllRoundExceptionHandler;
import com.common.interceptor.MyWebBinding;
import com.common.util.SpringUtils;
import com.common.web.ExceptionServlert;
import com.common.web.KaptchaController;

/**
 * SpringMvc配置
 * @author limk
 * @date 2018年2月10日 下午10:56:25
 * @version 1.0
 */
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.limk.jconfig", useDefaultFilters = false, includeFilters = {
		@Filter(type = FilterType.ANNOTATION, classes = Controller.class),
		@Filter(type = FilterType.ANNOTATION, classes = ControllerAdvice.class) })
@EnableAspectJAutoProxy(proxyTargetClass = true)
@Import(value = {KaptchaConfig.class })
public class WebMvcConfig extends WebMvcConfigurerAdapter {
	
	private static final Logger LOGGER = LogManager.getLogger(WebMvcConfig.class);

	/**
	 * 开启shiro权限注解的advisor
	 * @return
	 */
	@Bean(name = "controllerAuthorizationAttributeSourceAdvisor")
	public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
		AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
		ShiroConfig config = new ShiroConfig();
		advisor.setSecurityManager(config.securityManager());
		return advisor;
	}
	
	/**
	 * 注解POJO的映射
	 * @return
	 */
	@Bean
	public RequestMappingHandlerAdapter annotationMethodHandlerAdapter() {
		RequestMappingHandlerAdapter handlerAdapter = new RequestMappingHandlerAdapter();
		handlerAdapter.setCacheSeconds(0);
		handlerAdapter.setWebBindingInitializer(new MyWebBinding());
		return handlerAdapter;
	}
	
	/**
	 * beetl视图加载器
	 * @return
	 */
	@Bean(initMethod = "init")
	public BeetlGroupUtilConfiguration getBeetlGroupUtilConfiguration() {
		LOGGER.info("----------beetl视图----------");
		BeetlGroupUtilConfiguration configuration = new BeetlGroupUtilConfiguration();
		configuration.setConfigFileResource(new ClassPathResource("config/beetl.properties"));
		return configuration;
	}

	/**
	 * beetl视图
	 * @param beetlConfig
	 * @return
	 */
	@Bean
	public ViewResolver beetlSpringViewResolver(BeetlGroupUtilConfiguration beetlConfig) {
		BeetlSpringViewResolver resolver = new BeetlSpringViewResolver();
		resolver.setContentType("text/html;charset=UTF-8");
		resolver.setConfig(beetlConfig);
		resolver.setSuffix(".html");
		return resolver;
	}
	
	/**
	 * 消息转换器配置
	 * @param converters
	 * @see org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter#configureMessageConverters(java.util.List)
	 */
	@Override
	public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
		Charset charset = Charset.forName("UTF-8");
		
		List<MediaType> mediaTypeList = new ArrayList<>();
		mediaTypeList.add(new MediaType("application", "json", charset));
	    mediaTypeList.add(new MediaType("text", "html", charset));
		
	    // 设置返回字符串编码
	    StringHttpMessageConverter stringConverter = new StringHttpMessageConverter(charset);
	    stringConverter.setWriteAcceptCharset(false);
	    stringConverter.setSupportedMediaTypes(mediaTypeList);
	    converters.add(stringConverter);
	    
		// json转换器
		MappingJackson2HttpMessageConverter jacksonConverter = new MappingJackson2HttpMessageConverter();
		ObjectMapper objectMapper = jacksonConverter.getObjectMapper();
		objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
		objectMapper.setLocale(Locale.CHINA);
		objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));
		jacksonConverter.setSupportedMediaTypes(mediaTypeList);
		converters.add(jacksonConverter);
		
		super.configureMessageConverters(converters);
	}
	
	@Bean
	public LocalValidatorFactoryBean validatorFactory() {
		LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
		factoryBean.setProviderClass(HibernateValidator.class);
		ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
		String[] basenames = {"classpath:config/validation", "org/hibernate/validator/ValidationMessages"};
		messageSource.setBasenames(basenames);
		messageSource.setUseCodeAsDefaultMessage(false);
		messageSource.setDefaultEncoding("UTF-8");
		messageSource.setCacheMillis(60);
		factoryBean.setValidationMessageSource(messageSource);
		return factoryBean;
	}
	
	/**
	 * 多文件上传
	 *       bean必须写name属性且必须为multipartResolver，不然取不到文件对象
	 * @return
	 */
	@Bean(name = "multipartResolver")
	protected CommonsMultipartResolver multipartResolver() {
		CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
		//可以不设置
		// multipartResolver.setUploadTempDir(new FileSystemResource("/tmp"));
		// 2M
		multipartResolver.setMaxUploadSize(2097152);
		multipartResolver.setMaxInMemorySize(0);
		multipartResolver.setDefaultEncoding("UTF-8");
		return multipartResolver;
	}
	
	/**
	 * 异常处理
	 * @return
	 */
	@Bean
	public HandlerExceptionResolver handlerExceptionResolver() {
		return new AllRoundExceptionHandler();
	}
	
	/**
	 * 静态资源的处理
	 * @param registry
	 * @see org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter#addResourceHandlers(org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry)
	 */
	@Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/build/**").addResourceLocations("/build/");
        registry.addResourceHandler("/images/**").addResourceLocations("/images/");
        registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
    }
	
	/**
	 * kaptcha验证码
	 * @return
	 */
	@Bean
	public KaptchaController kaptchaController() {
		return new KaptchaController();
	}
	
	/**
	 * 异常转发
	 * @return
	 */
	@Bean
	public ExceptionServlert exceptionServlert() {
		return new ExceptionServlert();
	}
	
	/**
	 * spring工具
	 * @return
	 */
	@Bean
	public SpringUtils springUtils() {
		return new SpringUtils();
	}
	
}
